#include "QROHost_P.h"

static bool validateRegister(QROHost* that,QObject* obj);
static void registerRecursive(QROHost::Private* _P,QObject* root,QList<ObjectID> &registered);
static void observerDestruction(QROHost::Private* _P,ObjectData* data);
static void sendNewObjectUpdate(QROHost::Private* _P,const QList<ObjectID> &registered);
static QVariant packObjectData(QROHost::Private* _P,const QList<ObjectID> &registered);
static void unregisterObjectImp(QROHost::Private*_P,QObject* obj,ObjectID id);

QByteArray QROHost::Private::onInitialUpdate(RemoteInterfaceSourceImp* src){
    auto objPacket = packObjectData(this,m_objectDataMap.keys());
    auto propPacket = packAllPropertyData();
    auto parentPacket = packAllParentData();
    QVariantMap total;
    total["obj"] = objPacket;
    total["prop"] = propPacket;
    total["parent"] = parentPacket;
    auto data = compressVariant(total);
    return data;
}

void QROHost::Private::onRegisterObject(QObject* obj){
    if(!validateRegister(this->_Q,obj)) return;

    QList<ObjectID> registered;
    registerRecursive(this,obj,registered);//将数据注册到该系统中

    //将注册列表信息交给头结点
    m_objectDataMap[registered[0]]->registerList = registered;
    sendNewObjectUpdate(this,registered);//将该对象注册行为进行通知
}

void QROHost::Private::onUnregisterObject(QObject* obj){
    //将该对象及子对象都注销
    QList<ObjectID> unregistered;
    auto urlist = obj->findChildren<QObject*>(Qt::FindChildrenRecursively);
    urlist.prepend(obj);
    for(auto i:urlist)
    {
        auto id = m_objectIdMap.value(i,NullID);
        if(id)
        {
            unregisterObjectImp(this,i,id);
            unregistered << id;
        }
    }

    //删除掉该对象的属性更新数据
    clearPropertyQueue(unregistered);

    //如果该对象属于某个客户端，则通知客户端该对象已收回
    for(auto i:m_channels)
    {
        if(unregistered.contains(i.second->channel->ownedObjs()))
        {
            i.second->channel->setOwnedObjs(NullID);
        }
    }

    //将对象下线数据通知给客户端
    for(auto i : m_channels)
    {
        i.second->channel->removedObject(unregistered);
    }

    for(auto i:urlist)
    {
        emit _Q->objectOffline(i);
    }
}

static bool validateRegister(QROHost* that,QObject* obj){
    QString className = obj->metaObject()->className();

    if(!QRemoteObject2Meta::Instance()->isRegistered(className))
    {
        qDebug()<<"该类型没有被注册到远程系统中";
        return false;
    }

    if(QThread::currentThread() != that->thread())
    {
        qDebug()<<"该函数不能在本对象以外的线程内执行";
        return false;
    }

    if(that->thread() != obj->thread())
    {
        qDebug()<<"obj的线程和本对象的线程不相同，注册失败";
        return false;
    }

    return true;
}

static void registerRecursive(QROHost::Private* _P,QObject* root,QList<ObjectID> &registered)
{
    QString className = root->metaObject()->className();

    if(QRemoteObject2Meta::Instance()->isRegistered(className))
    {
        auto id = _P->allocObjectID();
        auto data = std::make_shared<ObjectData>();
        data->id = id;
        data->obj = root;
        _P->m_objectDataMap[id] =data;
        _P->m_objectIdMap[root] = id;
        auto metaObj = root->metaObject();
        for(const auto& i:QRemoteObject2Meta::Instance()->allPropData(className))
        {
            _P->observeProperty(metaObj,data.get(),root,i);//监控该对象的属性
        }

        _P->observerParent(metaObj,data.get(),root);
        observerDestruction(_P,data.get());
        root->setProperty("__RO_Net_Obj",QVariant::fromValue(_P->_Q));//注册时留下联系方式

        registered << id;
    }

    for(auto i:root->children())
    {
        registerRecursive(_P,i,registered);
    }
}

static void observerDestruction(QROHost::Private* _P,ObjectData* data){
    auto obj = data->obj;

    auto con = QObject::connect(obj,&QObject::destroyed,[=](){
        _P->_Q->unregisterObject(obj);
    });

    data->connections << con;
}

static void sendNewObjectUpdate(QROHost::Private* _P,const QList<ObjectID> &registered){
    QVariant v = packObjectData(_P,registered);
    auto data = compressVariant(v);
    for(auto i:_P->m_channels)
    {
        i.second->channel->newObject(data);
    }
}

//将对象数据转换成QVariant
static QVariant packObjectData(QROHost::Private* _P,const QList<ObjectID> &registered){
    QVariantList ret;
    for(auto headerId:registered)
    {
        QVariantMap single;
        auto data = _P->m_objectDataMap[headerId];
        if(data->registerList.empty())
            continue;//只有头节点能被打包

        auto meta = data->obj->metaObject();

        single["id"] = headerId;
        single["reglist"] = QVariant::fromValue(data->registerList);
        single["className"] = QVariant::fromValue(QString(meta->className()));

        ret << single;
    }
    return ret;
}


static void unregisterObjectImp(QROHost::Private*_P,QObject* obj,ObjectID id){
    auto data = _P->m_objectDataMap[id];
    for(auto i:data->connections)
    {
        QObject::disconnect(i);
    }
    _P->m_objectIdMap.remove(obj);
    _P->m_objectDataMap.remove(id);
}
